-
Notifications
You must be signed in to change notification settings - Fork 1
Add modifier support to PlaceholderFormatter #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
71f9492 to
0b046fc
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2 +/- ##
============================================
+ Coverage 99.04% 99.23% +0.18%
- Complexity 97 128 +31
============================================
Files 4 10 +6
Lines 210 261 +51
============================================
+ Hits 208 259 +51
Misses 2 2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
0b046fc to
3405a0a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request introduces a modifier system to PlaceholderFormatter, enabling fine-grained control over value transformations through a {{value|modifier}} syntax. The implementation uses a Chain of Responsibility pattern where modifiers can either handle transformations or pass values to the next modifier in the chain.
Changes:
- Introduced
Modifierinterface and two implementations:RawModifier(for clean scalar output) andStringifyModifier(default fallback) - Updated
PlaceholderFormatterto parse and apply modifiers using regex pattern/{{(\w+)(\|([^}]+))?}}/ - Added comprehensive documentation for modifiers including usage examples and custom modifier creation guide
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Modifier.php | New interface defining the modifier contract with modify() method |
| src/Modifier/RawModifier.php | Implements raw modifier for scalar values, bypassing stringifier formatting |
| src/Modifier/StringifyModifier.php | Wrapper modifier delegating to stringifier for value conversion |
| src/PlaceholderFormatter.php | Updated to parse modifier syntax and apply modifier chain instead of direct stringifier |
| tests/Unit/PlaceholderFormatterTest.php | Updated test to verify custom modifier support |
| tests/Unit/Formatter/RawModifierTest.php | Comprehensive test suite for RawModifier behavior |
| tests/Helper/TestingModifier.php | Test helper implementing Modifier interface for testing |
| docs/PlaceholderFormatter.md | Updated with modifier documentation and corrected examples |
| docs/modifiers/Modifiers.md | New overview documentation for modifier system |
| docs/modifiers/RawModifier.md | Detailed documentation for RawModifier |
| docs/modifiers/StringifyModifier.md | Detailed documentation for StringifyModifier |
| docs/modifiers/CreatingCustomModifiers.md | Guide for implementing custom modifiers |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot open a new pull request to apply changes based on the comments in this thread |
bb58a9f to
7641c33
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 31 out of 31 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@copilot open a new pull request to apply changes based on the comments in this thread |
c8002d9 to
faad3ea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 31 out of 31 changed files in this pull request and generated 16 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Although basic interpolation is useful, we often want to handle parameters
differently, not using the standard modification we apply to them. This commit
introduces modifiers, a concept already present in Respect\Validation.
We use a familiar `{{value|modifier}}` syntax found in many popular template
engines. To handle different types of modifiers, I implemented a Chain of
Responsibility, where each modifier delegates to the next one when it cannot
handle them.
The `StringifyModifier` remains the default fallback, ensuring that we don't
lose the robust type-handling we previously built, but I've also made some
changes to it. I realise that for Respect\Validation, we have a strong need to
add "quotes" around strings because they represent values that were just
validated, but in the context of placeholder replacement, this behaviour is
undesirable.
I've created the `AutoQuoteModifier`, which quotes scalar values by default and
provides a `|raw` pipe to bypass quoting when clean output is needed. This
allows Validation to retain its quoting behaviour while keeping the default
`PlaceholderFormatter` chain simple.
Assisted-by: OpenCode (GLM-4.6)
Assisted-by: Gemini 3 (Thinking)
faad3ea to
117e448
Compare
I based this new modifier on the `ListAndModifier` and `ListOrModifier` from Respect\Validation, but I wanted to improve on that design. Instead of maintaining two separate modifiers that repeat almost identical behavior just to change a conjunction, I’ve unified them into a single, versatile `ListModifier`. The power of this new approach lies in its flexibility; it allows for configurable conjunctions directly via the pipe syntax. This allows us to transform raw arrays into lists that actually make sense to a human reader. Whether we need a list joined by "and," "or," we can now produce more natural strings instead of falling back on a simple comma-separated list. Assisted-by: OpenCode (GLM-4.6) Assisted-by: Gemini 3 (Thinking)
I’ve ported the `QuoteModifier` from Respect\Validation, but I’ve taken a different approach for this implementation. While the original version relied on and implementation of `Quoter` (from Respect\Stringifier) dependency, I decided to remove it for this context. The `Quoter` interface system was designed to handle complex stringification levels and deep nesting—functionality that is simply overkill for this modifier. By stripping that dependency away, we’ve eliminated unnecessary complexity. A major benefit of this simplification is increased flexibility. Instead of being locked into a predefined quoting strategy, users can now define their preferred quoting character (such as ', ", or backticks) directly in the constructor. Assisted-by: OpenCode (GLM-4.6) Assisted-by: Gemini 3 (Thinking)
Another need we had in Respect\Validation was the ability to translate parameters into a different language, and I wanted to port that functionality to this library as well. I’ve ported the `TransModifier` from Validation, allowing us to bridge the gap between template interpolation and localization. Instead of reinventing the wheel, I’ve integrated this modifier with `symfony/translation`. By relying on the TranslatorInterface, we ensure robust translation ecosystems without being locked into a specific implementation. Assisted-by: OpenCode (GLM-4.6) Assisted-by: Gemini 3 (Thinking)
117e448 to
ce93a1d
Compare
While basic template interpolation is useful, we know that a one-size-fits-all stringification approach isn't always desirable. Sometimes you need to bypass the standard formatting logic or transform a value before it hits the final string. This commit introduces a flexible modifier system to solve that.
I’ve adopted the familiar
{{value|modifier}}syntax found in many popular template engines. To handle this transformation, I implemented a Chain of Responsibility pattern. This allows us to pipe values through specific logic, such as the new|rawmodifier, which provides clean scalar output by bypassing the default stringifier formatting.The
StringifyModifierremains the default fallback, ensuring that we don't lose the robust type-handling we previously built. By separating these transformations into an extensible modifier interface, we’ve made the system future-proof—users can now plug in custom transformations without touching the core formatting logic.This change turns our simple placeholder replacement into a proper interpolation engine, giving developers fine-grained control over how their data is presented.
Assisted-by: OpenCode (GLM-4.6)